package han.cirno.corrupt.components.refresh.impl

import androidx.core.content.pm.PackageInfoCompat
import han.cirno.corrupt.Application
import han.cirno.corrupt.R
import han.cirno.corrupt.activity.main.MainActivityViewModel
import han.cirno.corrupt.components.cclib.CCLib
import han.cirno.corrupt.components.refresh.BackgroundTask
import han.cirno.corrupt.components.refresh.StatusReceiver
import han.cirno.corrupt.components.school.SchoolImpl
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import java.io.ByteArrayOutputStream

class UpdateCheckTask(private val updateCheckEnabled:Boolean): BackgroundTask<MainActivityViewModel> {
    override val dispatcher: CoroutineDispatcher
        get()=Dispatchers.IO
    override val name: Int= R.string.main_refresh_updateCheck
    override suspend fun MainActivityViewModel.runTask(): BackgroundTask.Result {
        if (!updateCheckEnabled)return BackgroundTask.Result.Continue
        postStartStatus()
        try {
            ByteArrayOutputStream().use {
                val currentCode = PackageInfoCompat.getLongVersionCode(
                    Application.application.packageManager.getPackageInfo(
                        Application.application.packageName, 0
                    )
                )
                CCLib.instance.networkFetch("latest.ver", it) { _, _ -> }
                val versionString = String(it.toByteArray())
                val versionNameAndCode = versionString.split(",")
                val versionCode = versionNameAndCode[1].toLong()
                if (versionCode <= currentCode) {
                    postSuccessStatus()
                    return BackgroundTask.Result.Continue
                }
                updateVersionState.value=versionNameAndCode[0]
            }
            CCLib.instance.getManifest().onSuccess {
                val fileObject = CCLib.instance.getFileObject("latest.apk", it)
                updateSizeState.value=
                    "%.2f".format(((fileObject.subList.size - 1) * (1024 * 1024 - 1) + fileObject.lastSize) / 1024f / 1024f)
                updateAvailableState.value=true
            }
            postSuccessStatus()
        } catch (e: Exception) {
            postFailedStatus(e)
        }
        return BackgroundTask.Result.Continue
    }
}

class CheckAndFetchTask(
    private val info:String,
    override val name: Int?):BackgroundTask<MainActivityViewModel>{
    override val dispatcher: CoroutineDispatcher=Dispatchers.IO
    override suspend fun MainActivityViewModel.runTask(): BackgroundTask.Result {
        val impl = SchoolImpl.impl!!
        if (!impl.hasInfo(info))return BackgroundTask.Result.Continue
        postStartStatus()
        return if(impl.fetchInfo(info)
            .onSuccess { postSuccessStatus() }
            .onFailure { postFailedStatus(it) }
            .isSuccess) BackgroundTask.Result.Continue else BackgroundTask.Result.Abort
    }
}

class SimplePassTask<T:StatusReceiver>(
    override val dispatcher: CoroutineDispatcher=Dispatchers.Default,
    override val name: Int?=null,
    private val task:suspend ()->Unit
):BackgroundTask<T>{
    override suspend fun T.runTask(): BackgroundTask.Result=
        BackgroundTask.Result.Continue.apply { task() }
}

class GateTask<T: StatusReceiver>(private val pass:Boolean):BackgroundTask<T>{
    override val dispatcher: CoroutineDispatcher=Dispatchers.Default
    override val name: Int?=null
    override suspend fun T.runTask(): BackgroundTask.Result =
        if (pass) BackgroundTask.Result.Continue else BackgroundTask.Result.Abort
}